home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-08-14 | 78.6 KB | 2,794 lines | [TEXT/CWIE] |
- /*****************************************************************************
- TGraphic.cp
-
- Author: Timothy Carroll
- Apple Developer Technical Support
- timc@apple.com
-
- Copyright © 1996, 1997 Apple Computer, Inc., All Rights Reserved
-
- You may incorporate this sample code into your applications without
- restriction, though the sample code has been provided "AS IS" and the
- responsibility for its operation is 100% yours. However, what you are
- not permitted to do is to redistribute the source as "DSC Sample Code"
- after having made changes. If you're going to re-distribute the source,
- we require that you make it clear in the source that the code was
- descended from Apple Sample Code, but that you've made changes.
-
-
- Description
- -----------
-
- The TGraphic class encapsulates custom blitting of a graphic to an offscreen
- environment, such as a GWorld or a DrawSprocket buffer. The current blitters
- are refined versions of the RLE sprites in "Tips of the Mac Gaming Gurus".
- The core blitters do not do any work to align data to proper boundaries, so
- this code currently does not use doubles to move data (this would be
- horribly slow on the 603/604 chips).
-
- In addition to the drawing code, this class also encorporates hit testing
- graphics to each other or a single point, and using just the mask data to do
- an erase function. It also has some generalized loading and unloading code.
-
-
- Assumptions
- -----------
-
- Currently the encoders are only designed for 8-bit images, and assume that
- the same color table is being used between the TGraphic encoder and whatever
- the destination GWorld will be. The blitters don't really care and should
- work in anything >= 8 bits in depth, although they haven't been tested in
- anything other than 8 bits.
-
- Currently, this class is definitely not intended to be subclassed, so
- all the methods are non-virtual.
-
-
- Modification History
- --------------------
- 11/5/97 Replaced naked c-types with standard types from types.h.
-
- 9/18/97 CreateGraphic and the utility functions that it was based on
- were cleaned up. Now, the utility functions are responsible
- for cleaning up if they have an error. Fixed a few bugs in
- the CIcon code as well.
-
- 9/18/97 Updated code to Universal Headers 3.0. Cleaned up some of the
- comments. Revised code to use OSStatus everywhere.
-
- 5/22/97 Writes to resource file now call UpdateResFile.
-
- 5/21/97 The list that keeps the TGraphics was never being initialized.
- Perhaps the compiler automatically initializes the variables to
- NULL, otherwise I would have expected it to explode. We now
- explictly initialize the list variables.
-
- 5/21/97 No major changes or bugs fixed, but the list management code has
- been tidied up.
-
- 5/19/97 WriteToPICTResource could fail to restore the ports properly
- if QuickDraw returned an error. This is fixed now.
-
- 4/2/97 RELEASE OF 1.01
-
- 4/2/97 LoadFromGraphicResource called ReleaseResource twice because I
- duplicated some code to the cleanup section. Onyx's Spotlight
- spotted it. Buy it!
-
-
- 2/24/97 TGraphic relies on an application to allocate a color table. This
- handle is now declared inside TGraphic.h
-
- 2/24/97 Assert macros were moved to a separate file, which we explictly
- include. MrC can build it now.
-
- 1/23/97 If garbage were fit into the blitter, it is possible that we
- could draw before destPtr was initialized. This could never
- happen with a valid sprite, but the debug build now initializes
- the pointer to DEADBEEF to force a bus error. MrC's optimizer
- spotted this case in the code.
-
- *************************************************************************************/
-
- #include <Memory.h>
- #include <Resources.h>
-
- #include <Icons.h>
- #include "TGraphic.h"
- #include "Scaling.h"
-
-
- /*************************************************************************************
- Internal Declarations
-
- We define a number of constants used by the encoders and decoders. Each TGraphic
- consists of a number of drawing commands, each of which is a 32-bit unsigned int with
- an 8-bit operator and a 24-bit value, followed by zero or more bytes of associated data.
-
- Currently, each command is aligned to a 4-byte boundary, so a change in format would
- be required to use 8-byte floats.
- *************************************************************************************/
-
- enum
- {
- // An EndShape token must appear at the end of all TGraphics. The value is ignored.
- kEndShapeToken = 0L,
-
- // Each line must be preceded by a LineStart token, even lines with no drawing. The
- // data field is the offset to the next line, used for clipping and hit testing.
- kLineStartToken = 1L,
-
- // This is the only token that currently has additional data. The value field is the
- // number of bytes of pixel data, and the op-code is followed by that data. The data
- // is padded to a 4-byte boundary.
- kDrawPixelsToken = 2L,
-
- // This is the "draw" equivalent in the hit mask. We encode the hit mask separately
- // to allow for certain pixels to be drawn but not hit tested.
- kHitTestPixelsToken = 2L,
-
- // Skips a range of pixels, without drawing.
- kSkipPixelsToken = 3L,
-
- // The actual colors tested against in the hit mask. Alpha blending could be added,
- // but should be a different opcode to allow opaque pixels to be drawn quickly.
- kClearColorIndex = 0,
- kMaskColorIndex = 255
- };
-
- // This macro could be modified to support almost any alignment necessary.
- #define ALIGN_TO_NEXT_LONG(x) ( ((UInt32) x + 3) & ~3)
-
-
- // Standard declarations for our resource type and format.
-
- #define kTGraphicResourceType 'Gfic'
-
- struct TGraphicResHeader
- {
- UInt32 version;
- SInt16 depth;
- UInt16 flags;
- Rect bounds;
- UInt32 imageSize;
- UInt32 maskSize;
- };
- typedef TGraphicResHeader **TGraphicResHeaderHandle;
-
-
- // Preferred depth for the encoder.
- #define kPreferredDepth 8
-
-
- /*************************************************************************************
- TGraphic Allocation and List Management
-
- TGraphic objects are allocated and maintained in a list internally by this class.
- Each object is reference counted, to reduce the amount of time spent loading and
- preparing TGraphics. This is particularly important when you are loading sprites
- from PICT resources, since processing the sprites can take a long time.
-
- For truly high performance apps, you can preload all the TGraphics once, and use
- them, so that no time in the game loop actually gets spent preparing the sprites.
-
- The list is sorted by the TGraphic's resource ID, and uses standard C array indexing.
- The list is searched using a binary search.
- *************************************************************************************/
-
- static Handle gTGraphicList = NULL;
- static UInt32 gNumberGraphics = 0;
-
- static OSStatus InsertGraphicIntoList (TGraphic *theGraphic, UInt32 index);
- static OSStatus DeleteGraphicFromList (UInt32 index);
- static OSStatus SearchGraphicList (SInt16 resID, Boolean *found, UInt32 *index);
-
-
- /*************************************************************************************
- InsertGraphicIntoList
-
- This routine creates the list if it hasn't been initialized. Otherwise, it just
- inserts the TGraphic into the spot pointed to by the index. If an error occurs, the
- list is left in an indeterminate state.
- *************************************************************************************/
-
- OSStatus InsertGraphicIntoList (TGraphic *theGraphic, UInt32 index)
- {
- OSStatus theErr = noErr;
-
- #if qDebugging
- if (theGraphic == NULL)
- SIGNAL_ERROR ("\pError: Attempted to insert a NULL TGraphic in list.")
- if ((index < 0) || (index > gNumberGraphics))
- SIGNAL_ERROR ("\pError: Attempted to insert TGraphic at invalid index.")
- #endif
-
- // If we don't have a list, allocate one.
- if (gTGraphicList == NULL)
- {
- gNumberGraphics = 1;
-
- gTGraphicList = NewHandleClear (sizeof (TGraphic *));
- theErr = MemError();
- FAIL_OSERR (theErr, "\pERROR: Couldn't allocate TGraphic list.")
- FAIL_NIL (gTGraphicList, "\pERROR: Couldn't allocate TGraphic list.")
- }
- else
- // if we do have a list, expand it by one node
- {
- gNumberGraphics++;
-
- SetHandleSize(gTGraphicList,gNumberGraphics*sizeof(TGraphic *));
- theErr = MemError();
- FAIL_OSERR (theErr, "\pERROR: Couldn't resize TGraphic list")
- FAIL_NIL (gTGraphicList, "\pERROR: Couldn't resize TGraphic list")
-
- // Make room in the list for a node at the correct index.
- BlockMoveData( (*(TGraphic ***)gTGraphicList)+index,
- (*(TGraphic ***)gTGraphicList)+index+1,
- (gNumberGraphics - index-1) * sizeof(TGraphic *));
- }
-
- // Copy the TGraphic into the list.
- *((*(TGraphic ***) gTGraphicList)+index) = theGraphic;
-
- // We succeeded, cleanup and exit.
- goto cleanup;
-
- error:
- if (theErr == noErr)
- theErr = paramErr;
-
- cleanup:
- return theErr;
- }
-
-
- /*************************************************************************************
- DeleteGraphicFromList
-
- This routine removes the graphic from the list. If the list is then empty,
- it disposes of the handle.
- *************************************************************************************/
- OSStatus DeleteGraphicFromList (UInt32 index)
- {
- OSStatus theErr = noErr;
-
- #if qDebugging
- if ((index < 0) || (index > gNumberGraphics-1))
- SIGNAL_ERROR ("\pError: Attempted to delete outside of the list.")
- #endif
-
- gNumberGraphics--;
-
- // If there are elements in the list, slide them up and shrink the handle
- if (gNumberGraphics > 0)
- {
- BlockMoveData( (*(TGraphic ***)gTGraphicList)+index+1,
- (*(TGraphic ***)gTGraphicList)+index,
- (gNumberGraphics - index) * sizeof(TGraphic *));
-
- SetHandleSize((Handle) gTGraphicList,gNumberGraphics*sizeof(TGraphic *));
- theErr = MemError();
- FAIL_OSERR (theErr, "\pCouldn't resize the list handle")
- FAIL_NIL (gTGraphicList, "\pCouldn't resize the list handle")
- }
- else
- // Otherwise, the list is empty and we can dispose of it.
- {
- DisposeHandle (gTGraphicList);
- gTGraphicList = NULL;
- }
-
- // We succeeded, cleanup and exit.
- goto cleanup;
-
- error:
- if (theErr == noErr)
- theErr = paramErr;
- cleanup:
- return theErr;
- }
-
-
- /*************************************************************************************
- SearchGraphicList
-
- This routine searches for a TGraphic with the resID parameter. If it doesn't find
- one, the index it returns is the location where the new element should be inserted
- into the list.
- *************************************************************************************/
- OSStatus SearchGraphicList (SInt16 resID, Boolean *found, UInt32 *index)
- {
- OSStatus theErr = noErr;
- UInt32 low = 0;
- UInt32 high = gNumberGraphics;
- UInt32 tempIndex;
- SInt16 tempID;
- TGraphic *theItem = NULL;
-
- // For an empty list, we fall through immediately.
- while (low < high)
- {
- tempIndex = (low+high) >> 1;
- theItem = (*(TGraphic ***)gTGraphicList)[tempIndex];
- #if qDebugging
- FAIL_NIL (theItem, "\pERROR: List items should never be NULL!")
- #endif
- tempID = theItem->GetResID();
- if (resID == tempID)
- {
- // We found the object, return it
- *found = true;
- *index = tempIndex;
- goto cleanup;
- }
- else if (resID < tempID)
- // element must be below the current index
- high = tempIndex;
- else
- // element must be above the current index
- low = tempIndex+1;
- }
-
- // We fell through, so we didn't find the item in the list.
- *found = false;
- *index = (low+high) >> 1;
- goto cleanup;
-
- error:
- if (theErr == noErr)
- theErr = paramErr;
-
- cleanup:
- return theErr;
- }
-
- /*************************************************************************************
- TGraphic::NewGraphic
-
- This uses the list management code to create new graphics when needed, and to manage
- the reference counts.
- *************************************************************************************/
- TGraphic
- *TGraphic::NewGraphic (SInt16 resID)
- {
- OSStatus theErr = noErr;
- UInt32 listIndex;
- Boolean graphicAlreadyExists;
- TGraphic *newGraphic = NULL;
-
- theErr = SearchGraphicList (resID, &graphicAlreadyExists, &listIndex);
- FAIL_OSERR(theErr,"\pERROR: Failed to search the graphic list")
-
- if (graphicAlreadyExists)
- {
- // Bump the reference count on the existing graphic
- newGraphic = (*(TGraphic ***)gTGraphicList)[listIndex];
- newGraphic->AddReference();
- }
- else
- {
- // Create a new graphic and insert it into the list
- newGraphic = new TGraphic(resID);
- theErr = newGraphic->CreateGraphic();
- FAIL_OSERR(theErr,"\pERROR: Failed to create the new TGraphic.")
- theErr = InsertGraphicIntoList(newGraphic, listIndex);
- FAIL_OSERR(theErr, "\pERROR: Failed to insert TGraphic into list")
- newGraphic->AddReference();
- }
-
- // We succeeded, cleanup and return the TGraphic.
- goto cleanup;
-
- error:
- if (newGraphic != NULL)
- {
- delete newGraphic;
- newGraphic = NULL;
- }
-
- cleanup:
- return newGraphic;
- }
-
-
- /*************************************************************************************
- TGraphic::AddReference
- *************************************************************************************/
-
- void
- TGraphic::AddReference (void)
- {
- fReferenceCount++;
- }
-
-
- /*************************************************************************************
- TGraphic::DisposeReference
- *************************************************************************************/
-
- void
- TGraphic::DisposeReference (void)
- {
- fReferenceCount--;
-
- // If no one cares about us, remove us from the list and delete ourself.
-
- if (fReferenceCount == 0)
- {
- UInt32 listIndex;
- Boolean tableEntry;
- OSStatus theErr = noErr;
-
- theErr = SearchGraphicList (fResID, &tableEntry, &listIndex);
- #if qDebugging
- FAIL_OSERR (theErr, "\pERROR: List search reported an error")
- FAIL_FALSE (tableEntry, "\pERROR: TGraphic should have been in the list!")
- #endif
- theErr = DeleteGraphicFromList(listIndex);
- FAIL_OSERR (theErr, "\pFailed to delete graphic from the list")
-
- delete this;
- }
-
- error:
- return;
- }
-
-
-
- /*************************************************************************************
- TGraphic::TGraphic
-
- Just puts some sane values in the member variables.
- *************************************************************************************/
- TGraphic::TGraphic (SInt16 resID)
- {
- fResID = resID;
- fReferenceCount = 0;
- fImage = NULL;
- fHitMask = NULL;
-
- }
-
-
- /*************************************************************************************
- TGraphic::~TGraphic
-
- If we have real, allocated graphics, we should dispose of them.
- *************************************************************************************/
- TGraphic::~TGraphic (void)
- {
- DestroyGraphic();
- }
-
-
- /*************************************************************************************
- TGraphic::CreateGraphic
-
- Attempt to load the graphic from a resource. The preferred format is a pre-encoded
- sprite, since this loads very quickly, but if we don't find one, we'll use another
- format we recognize.
-
- This is useful because you can use other graphics formats while under development.
- *************************************************************************************/
- OSStatus TGraphic::CreateGraphic(void)
- {
- OSStatus theErr = noErr;
-
- theErr = LoadFromGraphicResource();
- if (theErr == noErr) goto cleanup;
-
- theErr = LoadFromPICTResource ();
- if (theErr == noErr) goto cleanup;
-
- theErr = LoadFromCIconResource ();
- if (theErr == noErr) goto cleanup;
-
- theErr = LoadFromICN8Resource ();
- if (theErr == noErr) goto cleanup;
-
- error:
-
- SIGNAL_ERROR ("\pError: No resource was found!")
- if (theErr == noErr)
- theErr = paramErr;
-
- cleanup:
- return theErr;
-
- }
-
-
- /*************************************************************************************
- TGraphic::DestroyGraphic
-
- All this needs to do is dispose of the image handle we created earlier.
- *************************************************************************************/
-
- OSStatus
- TGraphic::DestroyGraphic (void)
- {
- if (fImage != NULL)
- DisposeHandle (fImage);
- if (fHitMask != NULL)
- DisposeHandle (fHitMask);
-
- fImage = NULL;
- fHitMask = NULL;
-
- return noErr;
- }
-
-
-
- /*************************************************************************************
- TGraphic::LoadFromGraphicResource
-
- This routine loaded a previously encoded sprite.
- *************************************************************************************/
- OSStatus TGraphic::LoadFromGraphicResource(void)
- {
- Handle graphicResource = NULL;
- OSStatus theErr = noErr;
- Size imageSize = 0, maskSize = 0;
- TGraphicResHeaderHandle header;
-
- // STEP 1 -- determine if the resource exists and try to load it.
- graphicResource = Get1Resource (kTGraphicResourceType, fResID);
- theErr = ResError();
-
- if ((theErr != noErr) || (graphicResource == NULL))
- goto error;
-
- // STEP 2 -- Parse the resource header
-
- header = (TGraphicResHeaderHandle) graphicResource;
-
- // This code only parses version 0 formats.
- if ((**header).version != 0L)
- goto error;
-
- fBitDepth = (**header).depth;
- fFlags = (**header).flags;
- fBounds = (**header).bounds;
-
- imageSize = (**header).imageSize;
- maskSize = (**header).maskSize;
-
- // Step 3 -- Allocate the image and mask data and copy from the resource.
- fImage = NewHandle(imageSize);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pFailed to allocate the image handle")
- FAIL_NIL (fImage, "\pFailed to allocate the image handle")
-
- fHitMask = NewHandle (maskSize);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pFailed to allocate the mask handle")
- FAIL_NIL (fHitMask, "\pFailed to allocate the mask handle")
-
- BlockMoveData(((*graphicResource)+sizeof(TGraphicResHeader)), *fImage, imageSize);
- BlockMoveData(((*graphicResource)+sizeof(TGraphicResHeader)+imageSize), *fHitMask, maskSize);
-
- // We're done, cleanup and exit!
- goto cleanup;
-
- error:
-
- DestroyGraphic();
-
- if (theErr == noErr)
- theErr = paramErr;
-
- cleanup:
- if (graphicResource != NULL)
- ReleaseResource (graphicResource);
-
- return theErr;
- }
-
-
-
- /*************************************************************************************
- TGraphic::LoadFromPICTResource
-
- This routine reads a specially formatted pict, with image, drawing mask and hit mask
- going from left to right.
- *************************************************************************************/
- OSStatus
- TGraphic::LoadFromPICTResource (void)
- {
- PicHandle thePicture = NULL;
- OSStatus theErr = noErr;
- GWorldPtr graphicGWorld = NULL;
- PixMapHandle graphicPixMap = NULL;
- Rect pictRect;
-
- // STEP 1 -- Attempt to load the PICT
- thePicture = (PicHandle) Get1Resource ('PICT', fResID);
- theErr = ResError();
-
- if ((theErr != noErr) || (thePicture == NULL))
- goto error;
-
- // STEP 2 -- Normalize the picture rectangle, and use it to build a GWorld.
-
- pictRect = (**thePicture).picFrame;
-
- pictRect.right -= pictRect.left; pictRect.left = 0;
- pictRect.bottom -= pictRect.top; pictRect.top = 0;
-
- if (pictRect.right % 3 != 0)
- SIGNAL_ERROR ("\pImproper size pict to load as a graphic")
-
- theErr = NewGWorld(&graphicGWorld, kPreferredDepth, &pictRect, gAppColorTable, NULL, keepLocal);
- FAIL_OSERR (theErr, "\pCouldn't allocate GWorld for encoding")
-
- graphicPixMap = GetGWorldPixMap(graphicGWorld);
- FAIL_NIL (graphicPixMap, "\pCouldn't get the GWorld's PixMap")
- FAIL_FALSE ( LockPixels(graphicPixMap), "\pCouldn't lock GWorld PixMap")
-
- // Erase the GWorld and draw our picture
- {
- CGrafPtr savePort;
- GDHandle saveDevice;
-
- GetGWorld (&savePort, &saveDevice);
- SetGWorld (graphicGWorld, NULL);
-
- EraseRect (&pictRect);
- DrawPicture (thePicture, &pictRect);
-
- SetGWorld (savePort, saveDevice);
- }
-
- // STEP 4 -- feed the GWorld to the encoder.
-
- pictRect.right /=3;
- theErr = EncodeGraphic (graphicPixMap, &pictRect);
-
- if (theErr == noErr)
- goto cleanup;
-
- error:
- DestroyGraphic();
-
- if (theErr == noErr)
- theErr = paramErr;
-
- cleanup:
- if (thePicture != NULL)
- ReleaseResource ((Handle)thePicture);
-
- if (graphicGWorld != NULL)
- DisposeGWorld (graphicGWorld);
-
- return theErr;
-
- }
-
-
-
- /*************************************************************************************
- TGraphic::LoadFromICN8Resource
-
- This routine reads an ICL8 resource and uses the mask as both the drawing and hit
- mask. It isn't quite as versatile as the PICT format, but is probably easier to
- find tools to build sprites with.
- *************************************************************************************/
- OSStatus
- TGraphic::LoadFromICN8Resource (void)
- {
- OSStatus theErr = noErr;
- GWorldPtr graphicGWorld = NULL;
- PixMapHandle graphicPixMap = NULL;
- Rect graphicRect = {0,0,32,96};
- Rect iconRect = {0,0,32,32};
- Handle theIconSuite = NULL;
- RgnHandle theMask = NULL;
-
- // STEP 1 -- Attempt to load the icon
- theErr = GetIconSuite(&theIconSuite, fResID, svAllAvailableData);
-
- if ((theErr != noErr) || (theIconSuite == NULL))
- goto error;
-
- // STEP 2 -- Create a region from the IconSuite's mask
-
- theMask = NewRgn();
- theErr = QDError();
- FAIL_OSERR (theErr, "\pError: Failed to create the mask region")
- FAIL_NIL (theMask, "\pError: Failed to create the mask region")
-
- theErr = IconSuiteToRgn (theMask, &iconRect, atNone, theIconSuite);
- FAIL_OSERR (theErr, "\pError: Failed to load the mask data into the region")
- OffsetRgn (theMask, -(**theMask).rgnBBox.left, -(**theMask).rgnBBox.top);
-
- // STEP 3 -- Create a GWorld the size of 3 ICL8s.
-
- theErr = NewGWorld(&graphicGWorld, kPreferredDepth, &graphicRect, gAppColorTable, NULL, keepLocal);
- FAIL_OSERR (theErr, "\pCouldn't allocate GWorld for encoding")
-
- graphicPixMap = GetGWorldPixMap(graphicGWorld);
- FAIL_NIL (graphicPixMap, "\pCouldn't get the GWorld's PixMap")
- FAIL_FALSE ( LockPixels(graphicPixMap), "\pCouldn't lock GWorld PixMap")
-
- // STEP 4 -- Erase the GWorld and draw our icons
- {
- CGrafPtr savePort;
- GDHandle saveDevice;
-
- GetGWorld (&savePort, &saveDevice);
- SetGWorld (graphicGWorld, NULL);
-
- EraseRect (&graphicRect);
- theErr = PlotIconSuite(&iconRect, atNone, ttNone, theIconSuite); // icon
-
- OffsetRgn(theMask, 32, 0);
- FillRgn (theMask, &qd.black); // drawing mask
- OffsetRgn(theMask, 32, 0);
- FillRgn (theMask, &qd.black); // hit mask
-
- SetGWorld (savePort, saveDevice);
- }
-
- // STEP 5 -- feed the GWorld to the encoder.
-
- graphicRect.right /=3;
- theErr = EncodeGraphic (graphicPixMap, &graphicRect);
-
- if (theErr == noErr)
- goto cleanup;
-
- error:
- DestroyGraphic();
-
- if (theErr == noErr)
- theErr = paramErr;
-
- cleanup:
- if (theMask != NULL)
- DisposeRgn (theMask);
- if (theIconSuite != NULL)
- DisposeIconSuite (theIconSuite, true);
- if (graphicGWorld != NULL)
- DisposeGWorld (graphicGWorld);
-
- return theErr;
-
- }
-
-
- /*************************************************************************************
- TGraphic::LoadFromCIconResource
-
- This is much like LoadFromICN8Resource, but loads from a CIcon instead.
- *************************************************************************************/
- OSStatus
- TGraphic::LoadFromCIconResource (void)
- {
- OSStatus theErr = noErr;
- GWorldPtr graphicGWorld = NULL;
- PixMapHandle graphicPixMap = NULL;
- Rect graphicRect, iconRect;
- CIconHandle theCIcon = NULL;
- RgnHandle theMask = NULL;
-
- // STEP 1 -- Load the CIcon resource
- theCIcon = GetCIcon (fResID);
- theErr = ResError();
-
- if ((theCIcon == NULL) || (theErr != noErr))
- goto error;
-
- // STEP 2 -- Create a region from the Icon's mask
-
- theMask = NewRgn();
- theErr = QDError();
- FAIL_OSERR (theErr, "\pError: Failed to create the mask region")
- FAIL_NIL (theMask, "\pError: Failed to create the mask region")
-
- // Fill in the baseAddr of the BitMap.
- ( (**theCIcon).iconMask ).baseAddr = ( char* )(**theCIcon).iconMaskData;
-
- theErr = BitMapToRegion (theMask, &(**theCIcon).iconMask);
- FAIL_OSERR (theErr, "\pFailed to load the mask data into the region")
- OffsetRgn (theMask, -(**theMask).rgnBBox.left, -(**theMask).rgnBBox.top);
-
-
- // STEP 3 -- Build a GWorld the size of 3 CIcons
-
- iconRect = (**theCIcon).iconPMap.bounds;
- iconRect.right -= iconRect.left; iconRect.left = 0;
- iconRect.bottom -= iconRect.top; iconRect.top = 0;
-
- graphicRect = iconRect;
- graphicRect.right *= 3;
-
- theErr = NewGWorld(&graphicGWorld, kPreferredDepth, &graphicRect, gAppColorTable, NULL, keepLocal);
- FAIL_OSERR (theErr, "\pCouldn't allocate GWorld for encoding")
-
- graphicPixMap = GetGWorldPixMap(graphicGWorld);
- FAIL_NIL (graphicPixMap, "\pCouldn't get the GWorld's PixMap")
- FAIL_FALSE ( LockPixels(graphicPixMap), "\pCouldn't lock GWorld PixMap")
-
- // STEP 4 -- Erase the GWorld and draw our icons
- {
- CGrafPtr savePort;
- GDHandle saveDevice;
-
- GetGWorld (&savePort, &saveDevice);
- SetGWorld (graphicGWorld, NULL);
-
- EraseRect (&graphicRect);
-
- PlotCIcon (&iconRect, theCIcon); // image
- OffsetRgn(theMask, iconRect.right, 0);
- FillRgn (theMask, &qd.black); // draw mask
- OffsetRgn(theMask, iconRect.right, 0);
- FillRgn (theMask, &qd.black); // hit mask
-
- SetGWorld (savePort, saveDevice);
- }
-
- // STEP 5 -- feed the GWorld to the encoder.
-
- graphicRect.right /=3;
- theErr = EncodeGraphic (graphicPixMap, &graphicRect);
-
- if (theErr == noErr)
- goto cleanup;
-
- error:
- DestroyGraphic();
-
- if (theErr == noErr)
- theErr = paramErr;
-
- cleanup:
- if (theMask != NULL)
- DisposeRgn (theMask);
- if (theCIcon != NULL)
- DisposeCIcon (theCIcon);
- if (graphicGWorld != NULL)
- DisposeGWorld (graphicGWorld);
-
- return theErr;
-
- }
-
-
-
- /*************************************************************************************
- TGraphic::EncodeGraphic
-
- Takes a previously prepared pixmap and compresses it into our format.
- *************************************************************************************/
- OSStatus TGraphic::EncodeGraphic (PixMapHandle theGraphic, Rect *encodeRect)
- {
- OSStatus theErr = noErr;
-
- UInt16 shapeHeight; // the height of the shape
- UInt16 shapeWidth; // the width of the shape
-
- UInt32 rowBytes; // the rowbytes of our source pixmap
- UInt8 *baseAddr; // the base address of the source pixmap
-
- UInt8 *dataPtr; // points to where we are saving/encoding the data
- UInt8 *sourcePtr; // points to the graphics data we are saving in our image
- UInt8 *maskPtr; // points to whichever mask we are currently encoding
-
- UInt8 *sourceStartPtr; // points to the beginning of a source row.
-
- UInt32 yCounter; // a counter to scan the shape vertically
- UInt32 xCounter; // a counter to scan the shape horizontally
-
- Size newSize; // used to calculate the size of the new handle.
-
- // We preset the values to make the optimizer happy
- UInt8 *runTokenPtr = NULL; // where is the token for the current run
- UInt32 runCounter = 0; // how long is the current run?
-
- // STEP 1 -- precalculate the size of the shape.
- // Allocate enough memory to hold the RLE encoded shapes.
-
- shapeHeight = encodeRect->bottom - encodeRect->top;
- shapeWidth = encodeRect->right - encodeRect->left;
-
- // initialize the standard member data for our shape.
- fBounds.left = 0;
- fBounds.top = 0;
- fBounds.right = shapeWidth;
- fBounds.bottom = shapeHeight;
- fFlags = 0;
- fBitDepth = (**theGraphic).pixelSize;
-
- if (fBitDepth != 8)
- SIGNAL_ERROR ("\pError: This encoder only supports 8 bit images")
-
- //the memory totals are for the worse case shape.
-
- fImage = NewHandle (8*shapeHeight * shapeWidth + 4*shapeHeight +4);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pFailed to allocate a handle for the shape data")
- FAIL_NIL (fImage, "\pFailed to allocate a handle for the shape data")
-
- fHitMask = NewHandle (4*shapeHeight * shapeWidth + 4*shapeHeight +4);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pFailed to allocate a handle for the hit mask data")
- FAIL_NIL (fHitMask, "\pFailed to allocate a handle for the hit mask data")
-
- // Get some of the standard data we'll need when encoding the pixels
-
- baseAddr = (UInt8 *)GetPixBaseAddr( theGraphic );
- rowBytes = (*theGraphic)->rowBytes & 0x3fff;
-
-
- // STEP 2 -- Encode the shape data. We use a separate mask rather than using
- // chroma keying. This was mostly done to allow more flexibility in the
- // image design, but the other way works very similar.
-
- HLock (fImage);
- dataPtr = (UInt8 *) (*fImage);
-
- sourceStartPtr = baseAddr + rowBytes * encodeRect->top + encodeRect->left;
-
- // scan the shape row by row
- for( yCounter = 0; yCounter < shapeHeight; yCounter++ )
- {
- // store where the line starts, so we can fill in the lineStart token.
- UInt8 *lineStartPtr = dataPtr;
-
- // Flags to determine which run we are currently in. Initially false,
- // we don't start in a run.
- UInt8 drawRunFlag = false; // are we in a draw pixels run?
- UInt8 skipRunFlag = false; // are we in a skip pixels run?
-
- // reserve space for the lineStart token.
- dataPtr += sizeof( UInt32 );
-
- // move to the start of the row and begin scanning the pixels of the row.
- sourcePtr = sourceStartPtr;
- maskPtr = sourceStartPtr + shapeWidth;
-
- for( xCounter = 0; xCounter < shapeWidth; xCounter++ )
- {
- if ( *maskPtr == kClearColorIndex )
- {
- // Finish the draw run if we are in one.
- if ( drawRunFlag )
- {
- drawRunFlag = false;
-
- // create the draw token, and pad the line to a multiple of four.
- *( (UInt32 *)runTokenPtr ) = ( kDrawPixelsToken << 24 ) + runCounter;
-
- *( (UInt32 *)dataPtr ) = 0L;
- dataPtr = (UInt8 *) ALIGN_TO_NEXT_LONG(dataPtr);
- }
-
- // Start a new skip run, or continue the existing one.
- if ( skipRunFlag )
- {
- runCounter++;
- }
- else
- {
- // start a new skip run
- skipRunFlag = true;
- runCounter = 1;
- }
- }
- else
- {
- // Finish the skip run, if we're in one.
- if ( skipRunFlag )
- {
- skipRunFlag = false;
-
- // create the skip token
- *( ( UInt32 * )dataPtr ) = ( kSkipPixelsToken << 24 ) + runCounter;
- dataPtr += sizeof( UInt32 );
- }
-
- // Start a new draw run, or continue the existing one.
- if ( drawRunFlag )
- {
- // continue it
- runCounter++;
-
- // copy the pixel
- *dataPtr = *sourcePtr;
- dataPtr++;
- }
- else
- {
- // start one
- drawRunFlag = true;
- runCounter = 1;
-
- // save the location of the token (so we can fill it in later)
- runTokenPtr = dataPtr;
- dataPtr += sizeof( UInt32 );
-
- // copy the pixel
- *dataPtr = *sourcePtr;
- dataPtr++;
- }
- }
-
- // move to the next pixel
- sourcePtr++;
- maskPtr++;
- }
-
- // no need to write a skip at the end of a line, but we do need to finish
- // up a draw run if that's what we were working on.
- if( drawRunFlag )
- {
- // create the draw token
- *((UInt32 *) runTokenPtr) = ( kDrawPixelsToken << 24 ) + runCounter;
-
- // clear and pad to a mulitple of four
- *((UInt32 *)dataPtr ) = 0L;
- dataPtr = (UInt8 *) ALIGN_TO_NEXT_LONG(dataPtr);
- }
-
- // finish the line start token, and move to the next row.
- *( (UInt32 *)lineStartPtr ) = ( kLineStartToken << 24 ) + ( dataPtr - ( lineStartPtr + 4 ) );
- sourceStartPtr += rowBytes;
- }
-
- // create the end of shape token
- *((UInt32 *) dataPtr) = kEndShapeToken << 24;
- dataPtr += sizeof( UInt32 );
-
- // Resize the handle to match the real size of the shape
- HUnlock( fImage );
- newSize = dataPtr - (UInt8 *)( *fImage );
- SetHandleSize( fImage, newSize );
- theErr = MemError();
- FAIL_OSERR (theErr, "\p Failed to resize the handle")
-
- // STEP 3-- Encode the Mask data. Unlike the previous encoder, we don't have to copy any pixel
- // data.
-
- HLock (fHitMask);
- dataPtr = (UInt8 *)( *fHitMask );
-
- sourceStartPtr = baseAddr + rowBytes * encodeRect->top + encodeRect->left + shapeWidth+shapeWidth;
-
- // scan the shape row by row
- for( yCounter = 0; yCounter < shapeHeight; yCounter++ )
- {
- // we need to store where this line starts so we can fill in the lineStart token later.
- UInt8 *lineStartPtr = dataPtr;
- UInt8 drawRunFlag = false; // are we in a draw pixels run?
- UInt8 skipRunFlag = false; // are we in a skip pixels run?
-
- // reserve a place for the line start token.
- dataPtr += sizeof( UInt32 );
- maskPtr = sourceStartPtr;
-
- // scan each pixel of the mask.
- for( xCounter = 0; xCounter < shapeWidth; xCounter++ )
- {
- // is this pixel clear?
- if ( *maskPtr == kClearColorIndex )
- {
- // are we in a draw run?
- if ( drawRunFlag )
- {
- // end the draw run
- drawRunFlag = false;
-
- // create the draw token
- *( (UInt32 *)dataPtr ) = ( kDrawPixelsToken << 24 ) + runCounter;
- dataPtr += sizeof( UInt32 );
- }
-
- // are we in a skip run
- if ( skipRunFlag )
- {
- // continue it
- runCounter++;
- }
- else
- {
- // start one
- skipRunFlag = true;
- runCounter = 1;
- }
- }
- else
- {
- // are we in a skip run
- if ( skipRunFlag )
- {
- // end the skip run
- skipRunFlag = false;
- // create the skip token
- *( (UInt32 *)dataPtr ) = ( kSkipPixelsToken << 24 ) + runCounter;
- dataPtr += sizeof( UInt32 );
- }
-
- // are we in a draw run
- if ( drawRunFlag )
- {
- // continue it
- runCounter++;
- }
- else
- {
- // start one
- drawRunFlag = true;
- runCounter = 1;
- }
- }
-
- // move to the next byte
- maskPtr++;
- }
-
- // if we're finishing up a draw run, we need to write out the token
-
- if( drawRunFlag )
- {
- *( (UInt32 *)dataPtr ) = ( kDrawPixelsToken << 24 ) + runCounter;
- dataPtr += sizeof( UInt32 );
- }
-
- // create the line start token
- *( (UInt32 *)lineStartPtr ) = ( kLineStartToken << 24 ) + ( dataPtr - ( lineStartPtr + 4 ) );
-
- // move the row start to the next row
- sourceStartPtr += rowBytes;
- }
-
- // create the end of shape token
- *( (UInt32 *)dataPtr ) = kEndShapeToken << 24;
- dataPtr += sizeof( UInt32 );
-
-
-
- // Resize the handle to match the real size of the shape
- HUnlock( fHitMask );
- newSize = dataPtr - (UInt8 *)( *fHitMask );
- SetHandleSize( fHitMask, newSize );
- theErr = MemError();
- FAIL_OSERR (theErr, "\p Failed to resize the handle")
-
- goto cleanup;
-
- error:
-
- if (theErr == noErr)
- theErr = paramErr;
-
- cleanup:
- // cleanup is actually the responsibility of the calling function.
- return theErr;
- }
-
-
-
- /*************************************************************************************
- TGraphic::WriteToGraphicResource
-
- This takes a previously created graphic and writes out our custom resource format.
- *************************************************************************************/
- OSStatus
- TGraphic::WriteToGraphicResource (void)
- {
- Handle graphicResource = NULL;
- OSStatus theErr;
- Size imageSize;
- Size maskSize;
-
- imageSize = GetHandleSize(fImage);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pCouldn't obtain image handle size")
-
- maskSize = GetHandleSize (fHitMask);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pCouldn't obtain mask handle size")
-
- graphicResource = NewHandle (sizeof(TGraphicResHeader) + imageSize + maskSize);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pCouldn't allocate handle to hold new resource")
- FAIL_NIL (graphicResource, "\pCouldn't allocate handle to hold new resource")
-
- // Now to fill in the header and block move all of the data over into the new resource.
-
- (**(TGraphicResHeaderHandle)graphicResource).version = 0L;
- (**(TGraphicResHeaderHandle)graphicResource).depth = fBitDepth;
- (**(TGraphicResHeaderHandle)graphicResource).flags = fFlags;
- (**(TGraphicResHeaderHandle)graphicResource).bounds = fBounds;
- (**(TGraphicResHeaderHandle)graphicResource).imageSize = imageSize;
- (**(TGraphicResHeaderHandle)graphicResource).maskSize = maskSize;
-
- BlockMoveData(*fImage, ((*graphicResource)+sizeof(TGraphicResHeader)), imageSize);
- BlockMoveData(*fHitMask, ((*graphicResource)+sizeof(TGraphicResHeader)+imageSize), maskSize);
-
- // **TO DO: Check to see if there is already a resource with that ID!
-
- // Add the resource to the file.
- AddResource( graphicResource, kTGraphicResourceType, fResID, "\p" );
- theErr = ResError();
- FAIL_OSERR (theErr, "\pFailed to add the TGraphic resource to the file")
-
- WriteResource( graphicResource );
- theErr = ResError();
- FAIL_OSERR (theErr, "\pError: Failed to write the resource")
-
- UpdateResFile (CurResFile());
- theErr = ResError();
-
- ReleaseResource( graphicResource );
-
- return theErr;
-
- error:
- if (graphicResource != NULL)
- DisposeHandle (graphicResource);
- if (theErr == noErr)
- theErr = paramErr;
-
- return theErr;
- }
-
-
-
- /*************************************************************************************
- TGraphic::WriteToPICTResource
-
- This takes a previously created graphic and writes out a PICT with the 3 images.
- *************************************************************************************/
- OSStatus
- TGraphic::WriteToPICTResource (void)
- {
- Rect pictRect = fBounds;
- OSStatus theErr = NULL;
- GWorldPtr graphicGWorld = NULL;
- PixMapHandle graphicPixMap = NULL;
- PicHandle thePicture = NULL;
-
- // Create a locked GWorld with the proper depth, dimensions and color table.
- pictRect.right += (pictRect.right+pictRect.right);
-
- theErr = NewGWorld(&graphicGWorld, kPreferredDepth, &pictRect, gAppColorTable, NULL, keepLocal);
- FAIL_OSERR (theErr, "\pCouldn't allocate GWorld for encoding")
- graphicPixMap = GetGWorldPixMap(graphicGWorld);
- FAIL_NIL (graphicPixMap, "\pCouldn't get the GWorld's PixMap")
- FAIL_FALSE ( LockPixels(graphicPixMap), "\pCouldn't lock GWorld PixMap")
-
- // Erase the GWorld to white and draw the graphics into it.
- // HACK alert -- this code knows way too much about the information saved off in scaling.cp.
- // The real way to do this is to have some sort of structure analogous to a grafPort, and
- // switch the existing destination that way. Was slated for 1.1, but if that doesn't
- // happen, I'll move it back into this code.
-
- {
- CGrafPtr savePort;
- GDHandle saveDevice;
-
- Rect saveRect = gClipRect;
- PixMapHandle saveDestPixMap = gDestPixMap;
- PixMapHandle saveBackPixMap = gBackPixMap;
- UInt8 *saveDestBaseAddr = gDestBaseAddr;
- UInt8 *saveBackBaseAddr = gBackBaseAddr;
- UInt32 saveRowBytes = gRowBytes;
-
- SInt32 top, left;
- OpenCPicParams pictParams;
-
- GetGWorld (&savePort, &saveDevice);
- SetGWorld (graphicGWorld, NULL);
-
- ClipRect (&pictRect);
- EraseRect (&pictRect);
-
- SetDestinationBuffer (graphicPixMap, NULL);
-
- // finally, we draw the three images
- top = fBounds.top;
- left = fBounds.left;
-
- GraphicUnclipped (top, left);
- left += fBounds.right;
- DrawMaskUnclipped (top, left);
- left += fBounds.right;
- HitMaskUnclipped (top, left);
-
- // restore everything
-
- gClipRect = saveRect;
- gDestPixMap = saveDestPixMap;
- gBackPixMap = saveBackPixMap;
- gDestBaseAddr = saveDestBaseAddr;
- gBackBaseAddr = saveBackBaseAddr;
- gRowBytes = saveRowBytes;
-
- // create the pict
- pictParams.srcRect = pictRect;
- pictParams.hRes = 0x00480000;
- pictParams.vRes = 0x00480000;
- pictParams.version = -2;
- pictParams.reserved1 = 0;
- pictParams.reserved2 = 0;
-
- thePicture = OpenCPicture (&pictParams);
-
- ClipRect(&pictRect);
- CopyBits ((BitMap *) *graphicPixMap, (BitMap *) *graphicPixMap,
- &pictRect, &pictRect, srcCopy, NULL);
-
- ClosePicture();
- theErr = QDError();
-
- SetGWorld (savePort, saveDevice);
- }
-
- FAIL_NIL (thePicture, "\p Couldn't open the new picture")
- FAIL_OSERR (theErr, "\pFailed to create new picture")
-
- // Add the PICT to the resource fork.
-
- AddResource( (Handle) thePicture, 'PICT', fResID, "\p" );
- theErr = ResError();
- FAIL_OSERR (theErr, "\pFailed to add the PICT resource to the file")
-
- WriteResource( (Handle) thePicture );
- FAIL_OSERR (theErr, "\pError: Failed to write the resource")
-
- UpdateResFile (CurResFile());
- theErr = ResError();
- FAIL_OSERR (theErr, "\pError: Failed to update the resource fork")
-
- goto cleanup;
-
- error:
- if (theErr == noErr)
- theErr = paramErr;
-
-
- cleanup:
- if (graphicGWorld != NULL)
- DisposeGWorld (graphicGWorld);
-
- if (thePicture != NULL)
- {
- SInt8 memState = HGetState((Handle)thePicture);
- if (memState & 0x20)
- ReleaseResource ((Handle) thePicture);
- else
- DisposeHandle ((Handle) thePicture);
- }
-
- return theErr;
-
- }
-
-
-
- /*************************************************************************************
- TGraphic::LockGraphic
-
- Move all fo the data high and lock it down in memory.
- *************************************************************************************/
- OSStatus
- TGraphic::LockGraphic (void)
- {
- OSStatus theErr;
- MoveHHi (fImage);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pFailed to move the draw data high")
- HLock (fImage);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pFailed to lock the draw data")
-
- MoveHHi (fHitMask);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pFailed to move the mask data high")
- HLock (fHitMask);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pFailed to lock the mask data")
- return noErr;
-
- error:
- return theErr;
- }
-
-
- /*************************************************************************************
- TGraphic::UnlockGraphic
-
- Unlock the previously locked memory.
- *************************************************************************************/
-
- OSStatus
- TGraphic::UnlockGraphic (void)
- {
- OSStatus theErr;
- HUnlock (fImage);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pFailed to unlock the draw data")
- HUnlock (fHitMask);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pFailed to unlock the draw data")
- return noErr;
-
- error:
-
- return theErr;
- }
-
-
-
-
-
-
- /*************************************************************************************
- TGraphic::CopyImage
-
- This routine checks against the clipping rectangle and dispatches to the correct
- utility routine.
- *************************************************************************************/
- void
- TGraphic::CopyImage (SInt32 top, SInt32 left, Boolean useBackground)
- {
- #if qDebugging
- if (gDestPixMap == NULL)
- SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap")
-
- if (useBackground && (gBackPixMap == NULL))
- SIGNAL_ERROR ("\pAttepting to draw from an NULL background pixmap.")
-
- if (EmptyRect (&gClipRect))
- SIGNAL_ERROR ("\pEmpty Clipping Region")
- #endif
- // We'll do all our calculations in variables rather than use a structure.
- // hopefully this should speed things up
- SInt32 destTop, destBottom, destLeft, destRight;
-
- destTop = fBounds.top + top;
- destBottom = fBounds.bottom + top;
- destLeft = fBounds.left + left;
- destRight = fBounds.right + left;
-
- // determine if the spite needs to be drawn at all
- if (destTop >= gClipRect.bottom || destBottom <= gClipRect.top ||
- destLeft >= gClipRect.right || destRight <= gClipRect.left )
- // no need to draw, goodbye
- return;
-
- // determine if the sprite will be clipped
- if (destTop < gClipRect.top || destBottom > gClipRect.bottom ||
- destLeft < gClipRect.left || destRight > gClipRect.right)
- {
- // calculate the clipped bounding box in object local coordinates
- UInt32 clipTop, clipBottom, clipLeft, clipRight;
-
- clipTop = destTop < gClipRect.top ? gClipRect.top - destTop : 0;
- clipBottom = destBottom > gClipRect.bottom ? gClipRect.bottom-destTop : destBottom-destTop;
- clipLeft = destLeft < gClipRect.left ? gClipRect.left-destLeft : 0;
- clipRight = destRight > gClipRect.right ? gClipRect.right-destLeft : destRight-destLeft;
-
- if (useBackground)
- BackgroundClipped (destTop, destLeft, clipLeft, clipRight, clipTop, clipBottom);
- else
- GraphicClipped(destTop, destLeft, clipLeft, clipRight, clipTop, clipBottom );
- }
- else
- {
- if (useBackground)
- BackgroundUnclipped (destTop, destLeft);
- else
- GraphicUnclipped(destTop, destLeft );
- }
-
- error:
- return;
- }
-
-
- /*************************************************************************************
- TGraphic::HitTest
-
- This code walks the mask and returns true if the point intersects inside the mask.
-
- We make sure the point is inside the rectangle. If it in, we find the line in the
- shape that corresponds to that point and walk it, looking for lines inside the mask.
-
- Note that on the right side, we test greater than or equal, and on the left we only
- test less than. This is because the point that corresponds to a coord goes down and
- to the left. Think about it and you'll understand. :-)
- *************************************************************************************/
- Boolean
- TGraphic::HitTest (SInt32 v, SInt32 h)
- {
- if( v >= fBounds.bottom || v < fBounds.top ||
- h >= fBounds.right || h < fBounds.left )
- {
- return false;
- }
-
- // Our standard things to read the sprite
- UInt8 *dataPtr;
- UInt32 tokenOp;
- UInt32 tokenData;
-
- // We use these to count where we are in the image, to move to our point.
-
- UInt32 yCount = 0;
- UInt32 xCount = 0;
-
- // Move to the start of our hit testing data
- dataPtr = (UInt8 *)(*fHitMask);
-
- // Do a quick walk to the line which holds the point.
- while (v > 0)
- {
- v--;
- tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
-
- dataPtr += sizeof( UInt32 );
- dataPtr += tokenData;
- }
-
- // Skip the newLine token
- dataPtr += sizeof( UInt32 );
-
- // Start reading draw commands. Any end or newLine tokens mean we're done.
- // We'll exit out of the While loop via a return.
- do
- {
- // get a token
- tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
- tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
- dataPtr += sizeof( UInt32 );
-
- // depending on the token, we take an action
-
- // Note that line starts will be very common to begin with, so we'll move them up to the top
- switch( tokenOp )
- {
- case kHitTestPixelsToken:
-
- // We can only generate a hit in a draw command. If our point is between
- // xCount and xCount+tokenData, then it is on a drawn line, so return true.
- if ((xCount <= h) && (xCount+tokenData>h))
- return true;
- else if (xCount > h)
- return false;
- xCount += tokenData;
-
- break;
-
- case kSkipPixelsToken:
-
- xCount += tokenData;
-
- if (xCount > h)
- return false;
-
- break;
-
- case kLineStartToken:
- case kEndShapeToken:
- return false;
- #if qDebugging
- default:
- SIGNAL_ERROR ("\pInvalid TGraphic drawing operation")
- break;
- #endif
- }
- } while ( true );
-
- error:
- return false;
- }
-
-
-
- /*************************************************************************************
- TGraphic::Intersect
-
- This compares two TGraphic objects and two points in the SAME coordinate system
- and returns true if any two drawing commands intersect in the two objects.
- *************************************************************************************/
-
-
- Boolean TGraphic::Intersect (TGraphic *object1, TGraphic *object2, SInt32 v1, SInt32 h1, SInt32 v2, SInt32 h2)
- {
- SInt32 differenceX, differenceY;
-
- SInt32 object1right, object1bottom;
- SInt32 object2top, object2bottom, object2left, object2right;
-
- UInt32 xIntersectLeft, xIntersectRight, yHeight;
-
- Boolean intersect = false;
-
- // First, we sort the two objects in order of the x coordinate.
-
- if (h2 < h1)
- {
- SInt32 tempNum;
- TGraphic *tempGraphic;
-
- tempGraphic = object1; object1 = object2; object2 = tempGraphic;
-
- tempNum = h2; h2 = h1; h1 = tempNum;
- tempNum = v2; v2 = v1; v1 = tempNum;
- }
-
- // Next we calculate the bounding boxes of the two graphics and check to see if they overlap.
- // if they don't we can drop out and exit.
-
- differenceX = h2-h1;
- differenceY = v2-v1;
- // create two rectangles based on the object locations.
-
- object1right = (object1->fBounds).right;
- object1bottom = (object1->fBounds).bottom;
-
- object2left = differenceX;
- object2right = object2->fBounds.right + differenceX;
- object2top = differenceY;
- object2bottom = object2->fBounds.bottom + differenceY;
-
- if (object2bottom <= 0 || object2top >= object1bottom ||
- object2left >= object1right)
- goto done;
-
- // Next we want to do some calculations that we'll use to parse the list. Basically, we are
- // determining the coordinates we're going to use for to search for an intersection.
-
- xIntersectLeft = object2left;
- xIntersectRight = object1right > object2right ? object2right : object1right;
-
- {
- UInt32 yTop, yBottom;
-
- yTop = object2top > 0 ? object2top : 0;
- yBottom = object1bottom > object2bottom ? object2bottom : object1bottom;
-
- yHeight = yBottom-yTop; // the number of row's we'll need to test.
- }
-
- // These will hold whichever command we are looking at.
- UInt32 tokenOp;
- UInt32 tokenData;
-
- // These will hold our current pointers to commands for both objects.
- UInt8 *dataPtr1, *dataPtr2;
-
- // We'll precalculate the pointers for the next line, to make it easier to change
- // both objects at the same time.
-
- UInt8 *nextDataPtr1, *nextDataPtr2;
-
- // Whenever we hit an end of line, we need to drop out and make sure both data pointers are incremented.
-
- UInt8 lineDone = false;
-
- // We occasionally need to drop out of just the inner loop -- we'll set this to true.
-
- UInt8 innerObjectDone = false;
-
- // These count where we're at in each of the two object's scanlines.
-
- UInt32 xCount1 = 0, xCount2 = 0;
-
-
-
- // move to the start of each shape's data.
- dataPtr1 = (UInt8 *)(*(object1->fHitMask));
- dataPtr2 = (UInt8 *)(*(object2->fHitMask));
-
- // One of the two objects will probably need to be advanced in the vertical coordinate to put us
- // in the correct position. We'll count out a number of skips equal to the previous y difference
- // we calculated.
- // now we need to skip lines until we get to the correct starting location for each shape.
- // With the current encoder, all objects start with startline commands. So we'll cound out a number
- // of skips equal to the intersection rect's top Y coordinate.
- if (differenceY > 0)
- do
- {
- tokenData = ( *( (UInt32 *)dataPtr1 ) ) & 0x00ffffff;
-
- dataPtr1 += sizeof( UInt32 );
- dataPtr1 += tokenData;
- }
- while (--differenceY > 0);
- else
- while (differenceY++ < 0)
- {
- tokenData = ( *( (UInt32 *)dataPtr2 ) ) & 0x00ffffff;
-
- dataPtr2 += sizeof( UInt32 );
- dataPtr2 += tokenData;
- }
- // Now we're ready to begin. For the most part, we loop inside object1 looking for a draw command
- // inside the intersected area. If we find one, then we run a second loop inside this, looking
- // for a draw commmand in object2 that intersects the one from object1. If we find one, we return
- // true. If we hit the end of the shape, or the intersected area, we return false.
-
- // If we hit the end of a particular line, then we drop out of both loops and advance the pointers
- // appropriately, and run the next line.
-
- do
- {
- // First, we retrieve the start of line command for each of the objects -- from this we can
- // calculate the pointers for the next scanline, which we use when we drop out of the search
- // loops.
- tokenOp = ( *( (UInt32 *)dataPtr1 ) ) >> 24;
- tokenData = ( *( (UInt32 *)dataPtr1 ) ) & 0x00ffffff;
-
- dataPtr1 += sizeof( UInt32 );
- nextDataPtr1 = dataPtr1+ tokenData;
-
- tokenOp = ( *( (UInt32 *)dataPtr2 ) ) >> 24;
- tokenData = ( *( (UInt32 *)dataPtr2 ) ) & 0x00ffffff;
-
- dataPtr2 += sizeof( UInt32 );
- nextDataPtr2 = dataPtr2+ tokenData;
-
- // reset our booleans and our horizontal positions.
- lineDone = false;
- xCount1 = 0;
- xCount2 = xIntersectLeft;
-
-
-
- while (!lineDone)
- {
- // Loop in object1 looking for a draw command inside the intersected area. If we hit the end
- // of our intersected area or a new line token, we'll drop out of the loop.
- // Get the next operation
- tokenOp = ( *( (UInt32 *)dataPtr1 ) ) >> 24;
- tokenData = ( *( (UInt32 *)dataPtr1 ) ) & 0x00ffffff;
-
- dataPtr1 += sizeof( UInt32 );
-
- switch (tokenOp)
- {
- case kHitTestPixelsToken:
- // kDrawPixels is the ugly token to parse, because if the drawing command
- // is inside the intersected area, we have to run ANOTHER loop for object 2.
- {
- UInt32 x1RightDraw = xCount1+tokenData;
- UInt32 x1LeftDraw = xCount1;
- // skip to next command
-
- // if we're still to the left of our intersection, skip to next set
- if (x1RightDraw <= xIntersectLeft)
- break;
-
- // pin left side to intersection
- if (x1LeftDraw < xIntersectLeft)
- x1LeftDraw = xIntersectLeft;
-
- // pin to right side to intersection
- if (x1RightDraw > xIntersectRight)
- x1RightDraw = xIntersectRight;
-
- // Now we loop inside of object 2 until we find an intersecting draw command
- // or skip past object1's draw area.
- innerObjectDone = false;
-
- while (!(lineDone || innerObjectDone))
- {
- tokenOp = ( *( (UInt32 *)dataPtr2 ) ) >> 24;
- tokenData = ( *( (UInt32 *)dataPtr2 ) ) & 0x00ffffff;
-
- switch (tokenOp)
- {
- case kHitTestPixelsToken:
- // Now we can finally check for an intersection!!
-
- if (!(((xCount2 <= x1LeftDraw) && (xCount2+tokenData <= x1LeftDraw)) ||
- ((xCount2 >= x1RightDraw) && (xCount2+tokenData > x1RightDraw))))
- {
- intersect = true;
- goto done;
- }
-
- // if we are to the right of object1's drawing command, then we drop out of
- // the object2 loop. Note that in this case we do not advance to the next
- // draw command in object2, as we might need to check the next drawing command
- // in object1 against it.
-
- if (xCount2+tokenData >= x1RightDraw)
- {
- innerObjectDone = true;
- }
- else
- {
- xCount2 += tokenData;
- dataPtr2 += sizeof( UInt32 );
- }
- break;
-
- case kSkipPixelsToken:
- xCount2 += tokenData;
- dataPtr2 += sizeof( UInt32 );
- if (xCount2 > xIntersectRight)
- innerObjectDone = true;
- break;
-
- case kLineStartToken:
- lineDone = true;
- break;
- case kEndShapeToken:
- goto done;
- break;
- #if qDebugging
- default:
- Debugger();
- break;
- #endif
- } // end inner switch
- } // end inner while loop
-
- // and make sure we exit if were at the end of the line in object1.
- if (xCount1 >= xIntersectRight)
- lineDone = true;
- }
- break;
-
- case kSkipPixelsToken:
- xCount1 += tokenData;
- if (xCount1 >= xIntersectRight)
- lineDone = true;
- break;
- case kLineStartToken:
- lineDone = true;
- break;
- case kEndShapeToken:
- goto done;
- break;
- #if qDebugging
- default:
- Debugger();
- break;
- #endif
- }
- }
- // skip to the next line for both and increment the count.
- dataPtr1 = nextDataPtr1;
- dataPtr2 = nextDataPtr2;
- } while (--yHeight > 0);
-
-
- done:
- // If we got this far, we've dropped out of the bottom of the intersect area.
- return intersect;
- }
-
-
-
- /*************************************************************************************
- TGraphic::GraphicClipped
- *************************************************************************************/
-
- void
- TGraphic::GraphicClipped (SInt32 top, SInt32 left, UInt32 clipLeft, UInt32 clipRight,
- UInt32 clipTop, UInt32 clipBottom)
-
- // This routine is almost identical to the one from Tips of the Mac Game Programming Gurus.
- {
- UInt8 *rowStart; // the pointer to the start of this row
- UInt8 *srcPtr; // the current position in the sprite data
- UInt8 *destPtr; // the current position in the destination pixmap
- UInt32 miscCounter; // a counter for various purposes
- UInt32 extraCounter; // a counter for right clippling purposes ( how much extra was there? )
- UInt32 tokenOp; // the op code from the token
- UInt32 tokenData; // the data from the token
- UInt32 yCount; // how many lines do we have left to scan.
- UInt32 xCount; // where are we in this line?
-
- // Determine the actual clipping area we're going to need to draw, we do these as UInt32s because
- // that's what we'll use when drawing.
-
- // set up the initial count of rows we'll want to search
- yCount = clipBottom-clipTop;
-
- // determine characteristics about the pixmap
- rowStart = gDestBaseAddr + (top + clipTop) * gRowBytes + left;
-
- // move to the start of the image data. We'll do a quick skip of any initial pixel rows that we don't
- // need to worry about.
- srcPtr = (UInt8 *)( *fImage);
-
- // We do this to get rid of an optimizer error. Normally, the destPtr and xCount get
- // set as part of the first token that gets interpreted by the loop.
-
- #if qDebugging
- destPtr = (UInt8 *)0xDDDDDDDD;
- #else
- destPtr = rowStart;
- #endif
- xCount = 0;
-
- while (clipTop > 0)
- {
- clipTop--;
- tokenData = ( *( (UInt32 *)srcPtr ) ) & 0x00ffffff;
- srcPtr += sizeof( UInt32 ) + tokenData;
- }
-
- // start the loop
- do
- {
- // get a token
- tokenOp = ( *( (UInt32 *)srcPtr ) ) >> 24;
- tokenData = ( *( (UInt32 *)srcPtr ) ) & 0x00ffffff;
- srcPtr += sizeof( UInt32 );
-
- // depending on the token
- switch( tokenOp )
- {
- case kDrawPixelsToken:
- miscCounter = tokenData;
- extraCounter = 0;
-
- // if we need to, clip to the left
- if( xCount < clipLeft )
- {
- // if this run does not appear at all, don't draw it
- if ( miscCounter < clipLeft - xCount )
- {
- destPtr += miscCounter;
- xCount += miscCounter;
- miscCounter = ALIGN_TO_NEXT_LONG(miscCounter);
- srcPtr += miscCounter;
-
- break;
- }
- else
- {
- // if it does, skip to where we can draw
- miscCounter -= clipLeft - xCount;
- destPtr += clipLeft - xCount;
- srcPtr += clipLeft - xCount;
- xCount = clipLeft;
- }
- }
-
- // if we need to, clip to the right
- if ( xCount + miscCounter > clipRight )
- {
- // if this run does not appear at all, skip it
- if ( xCount > clipRight )
- {
- // once xCount is greater than xRight, no drawing commands will ever
- // be issued on that line, so I changed the "gurus" code, which was actually
- // wasting a couple of instructions setting variables that aren't needed.
- //destPtr += miscCounter;
- //xCount += miscCounter;
- miscCounter = ALIGN_TO_NEXT_LONG(miscCounter);
- srcPtr += miscCounter;
- break;
- }
- else
- {
- // if it does, setup to draw what we can
- extraCounter = (xCount + miscCounter) - clipRight;
- miscCounter -= extraCounter;
- }
- }
-
- // adjust xCount for the run
- xCount += miscCounter;
-
- // This blit loop is optimized to move 32 bytes or less. On 604 machines, using an 8 byte move
- // is faster in those rare cases where you can get them to align, and way slower when they don't.
- // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
-
-
- {
- register UInt32 sixteenblits, blitloop;
- sixteenblits = miscCounter >> 4;
- for ( blitloop = 0; blitloop < sixteenblits; blitloop++)
- {
- register UInt32 temp1, temp2, temp3, temp4;
- temp1 = ((UInt32 *) srcPtr)[0];
- temp2 = ((UInt32 *) srcPtr)[1];
- temp3 = ((UInt32 *) srcPtr)[2];
- temp4 = ((UInt32 *) srcPtr)[3];
- ((UInt32 *) destPtr)[0] = temp1;
- ((UInt32 *) destPtr)[1] = temp2;
- ((UInt32 *) destPtr)[2] = temp3;
- ((UInt32 *) destPtr)[3] = temp4;
- srcPtr += 16;
- destPtr += 16;
- }
- // move any remaining data, up to 15 bytes total
- if (miscCounter & 0x8)
- {
- register UInt32 temp1, temp2;
- temp1 = ((UInt32 *) srcPtr)[0];
- temp2 = ((UInt32 *) srcPtr)[1];
- ((UInt32 *) destPtr)[0] = temp1;
- ((UInt32 *) destPtr)[1] = temp2;
- srcPtr += 8;
- destPtr += 8;
- }
- if (miscCounter & 0x4)
- {
- register UInt32 temp1;
- temp1 = *((UInt32 *) srcPtr);
- srcPtr +=4;
- *((UInt32 *) destPtr) = temp1;
- destPtr +=4;
- }
- if (miscCounter & 0x2)
- {
- register UInt16 temp1;
- temp1 = *((UInt16 *) srcPtr);
- srcPtr +=2;
- *((UInt16 *) destPtr) = temp1;
- destPtr +=2;
- }
- if (miscCounter & 0x1)
- *destPtr++ = *srcPtr++;
-
- }
-
- // adjust for right clipping
- destPtr += extraCounter;
- srcPtr += extraCounter;
- xCount += extraCounter;
-
- // adjust for the padding
- srcPtr = (UInt8 *) ALIGN_TO_NEXT_LONG(srcPtr);
- break;
-
- case kSkipPixelsToken:
- destPtr += tokenData;
- xCount += tokenData;
- break;
-
- case kLineStartToken:
- // check to see if we're done drawing
- if (yCount == 0)
- return;
- else
- {
- // set all the counters up
- yCount--;
- xCount = 0;
- // set up the destination pointer
- destPtr = rowStart;
- rowStart += gRowBytes;
- }
- break;
-
- case kEndShapeToken:
- // exit.
- return;
- break;
- #if qDebugging
- default:
- // we should never get here
- Debugger();
- break;
- #endif
- }
- } while (true);
- }
-
-
- /*************************************************************************************
- TGraphic::GraphicUnclipped
- *************************************************************************************/
-
- void
- TGraphic::GraphicUnclipped (SInt32 top, SInt32 left)
- {
- // This routine is almost identical to the one from Tips of the Mac Game Programming Gurus.
-
- UInt8 *rowStart; // the pointer to the start of this row
- UInt8 *srcPtr; // the current position in the sprite data
- UInt8 *destPtr; // the current position in the destination pixmap
- UInt32 miscCounter; // a counter for various purposes
- UInt32 tokenOp; // the op code from the token
- UInt32 tokenData; // the data from the token
-
-
- // If we are debugging and we have an invalid graphic, then destPtr might never be set
- // up correctly. This will force us to attempt to write to a bad location in memory.
-
- // determine characteristics about the pixmap
- rowStart = gDestBaseAddr + top * gRowBytes + left;
-
- // move to the start of the image data.
- srcPtr = (UInt8 *)( *fImage );
-
- #if qDebugging
- destPtr = (UInt8 *) 0xDDDDDDDD;
- #else
- destPtr = rowStart;
- #endif
-
- // Start looping
- do
- {
- // get a token
- tokenOp = ( *( (UInt32 *)srcPtr ) ) >> 24;
- tokenData = ( *( (UInt32 *)srcPtr ) ) & 0x00ffffff;
- srcPtr += sizeof( UInt32 );
-
- // depending on the token
- switch( tokenOp )
- {
- case kDrawPixelsToken:
- miscCounter = tokenData;
-
- // This blit loop is optimized to move 32 bytes or less. On 604 machines, using an 8 byte move
- // is faster in those rare cases where you can get them to align, and way slower when they don't.
- // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
-
-
- {
- register UInt32 sixteenblits, blitloop;
- sixteenblits = miscCounter >> 4;
- for ( blitloop = 0; blitloop < sixteenblits; blitloop++)
- {
- register UInt32 temp1, temp2, temp3, temp4;
- temp1 = ((UInt32 *) srcPtr)[0];
- temp2 = ((UInt32 *) srcPtr)[1];
- temp3 = ((UInt32 *) srcPtr)[2];
- temp4 = ((UInt32 *) srcPtr)[3];
- ((UInt32 *) destPtr)[0] = temp1;
- ((UInt32 *) destPtr)[1] = temp2;
- ((UInt32 *) destPtr)[2] = temp3;
- ((UInt32 *) destPtr)[3] = temp4;
- srcPtr += 16;
- destPtr += 16;
- }
- // move any remaining data, up to 15 bytes total
- if (miscCounter & 0x8)
- {
- register UInt32 temp1, temp2;
- temp1 = ((UInt32 *) srcPtr)[0];
- temp2 = ((UInt32 *) srcPtr)[1];
- ((UInt32 *) destPtr)[0] = temp1;
- ((UInt32 *) destPtr)[1] = temp2;
- srcPtr += 8;
- destPtr += 8;
- }
- if (miscCounter & 0x4)
- {
- register UInt32 temp1;
- temp1 = *((UInt32 *) srcPtr);
- srcPtr +=4;
- *((UInt32 *) destPtr) = temp1;
- destPtr +=4;
- }
- if (miscCounter & 0x2)
- {
- register UInt16 temp1;
- temp1 = *((UInt16 *) srcPtr);
- srcPtr +=2;
- *((UInt16 *) destPtr) = temp1;
- destPtr +=2;
- }
- if (miscCounter & 0x1)
- *destPtr++ = *srcPtr++;
-
- }
-
- // adjust for the padding
- srcPtr = (UInt8 *) ALIGN_TO_NEXT_LONG(srcPtr);
- break;
-
- case kSkipPixelsToken:
- destPtr += tokenData;
- break;
-
- case kLineStartToken:
- // set up the destination pointer
- destPtr = rowStart;
- rowStart += gRowBytes;
- break;
-
- case kEndShapeToken:
- // exit the routine
- return;
- break;
- #if qDebugging
- default:
- // we should never get here
- Debugger();
- break;
- #endif
- }
- } while( true );
- }
-
-
- /*************************************************************************************
- TGraphic::BackgroundClipped
-
- The Background routines work similarly to the standard graphic drawing routines,
- but we keep an additional pointer to the destination graphics world, and we draw from
- it, not the graphic data. Later, we might optimize this routine further as we know
- the two are always in sync.
- *************************************************************************************/
-
-
- void
- TGraphic::BackgroundClipped (SInt32 top, SInt32 left, UInt32 clipLeft, UInt32 clipRight,
- UInt32 clipTop, UInt32 clipBottom)
- {
- UInt8 *sourceRowStart; // the pointer to the start of this row in the source
- UInt8 *destRowStart; // the pointer to the start of this row in the dest
- UInt8 *srcPtr; // the current position in the source pixmap
- UInt8 *destPtr; // the current position in the destination pixmap
- UInt8 *dataPtr; // the current position in the sprite data;
- UInt32 miscCounter; // a counter for various purposes
- UInt32 extraCounter; // a counter for right clippling purposes ( how much extra was there? )
- UInt32 tokenOp; // the op code from the token
- UInt32 tokenData; // the data from the token
- UInt32 yCount; // how many lines do we still have to draw
- UInt32 xCount; // where are we in this line?
-
- // determine characteristics about the pixmap
- sourceRowStart = gBackBaseAddr + (top + clipTop) * gRowBytes + left;
- destRowStart = gDestBaseAddr + (top + clipTop) * gRowBytes + left;
-
- // move to the start of the image data. We'll do a quick skip of any initial pixel
- // rows that we don't need to worry about.
- dataPtr = (UInt8 *)( *fImage);
-
- yCount = clipBottom - clipTop;
-
- #if qDebugging
- srcPtr = (UInt8 *) 0xDDDDDDDD;
- destPtr = (UInt8 *) 0xDDDDDDDD;
- #else
- srcPtr = sourceRowStart;
- destPtr = destRowStart;
- #endif
- xCount = 0;
-
- while (clipTop > 0)
- {
- clipTop--;
- tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
- dataPtr += sizeof( UInt32 ) + tokenData;
- }
-
- do
- {
- // get a token
- tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
- tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
- dataPtr += sizeof( UInt32 );
-
- // depending on the token
- switch( tokenOp )
- {
- case kDrawPixelsToken:
- miscCounter = tokenData;
- extraCounter = 0;
-
- // advance the data pointer for free
- tokenData = ALIGN_TO_NEXT_LONG (tokenData);
- dataPtr += tokenData;
-
- // if we need to, clip to the left
- if (xCount < clipLeft )
- {
- // if this run does not appear at all, don't draw it
- if ( miscCounter < clipLeft - xCount )
- {
- destPtr += miscCounter;
- srcPtr += miscCounter;
- xCount += miscCounter;
- break;
- }
- else
- {
- // if it does, skip to where we can draw
- miscCounter -= clipLeft - xCount;
- destPtr += clipLeft - xCount;
- srcPtr += clipLeft - xCount;
- xCount = clipLeft;
- }
- }
-
- // if we need to, clip to the right
- if ( xCount + miscCounter > clipRight )
- {
- // if this run does not appear at all, skip it
- if ( xCount > clipRight )
- // once xCount is greater than xRight, no drawing commands will ever
- // be issued on that line, so I changed the "gurus" code, which was actually
- // wasting a couple of instructions setting variables that aren't needed.
- //destPtr += miscCounter;
- //srcPtr += miscCounter;
- //xCount += miscCounter;
- break;
- else
- {
- // if it does, setup to draw what we can
- extraCounter = (xCount + miscCounter) - clipRight;
- miscCounter -= extraCounter;
- }
- }
-
- // adjust xCount for the run
- xCount += miscCounter;
- // This blit loop is optimized to move 32 bytes or less. On 604 machines, using an 8 byte move
- // is faster in those rare cases where you can get them to align, and way slower when they don't.
- // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
-
-
- {
- register UInt32 sixteenblits, blitloop;
- sixteenblits = miscCounter >> 4;
- for ( blitloop = 0; blitloop < sixteenblits; blitloop++)
- {
- register UInt32 temp1, temp2, temp3, temp4;
- temp1 = ((UInt32 *) srcPtr)[0];
- temp2 = ((UInt32 *) srcPtr)[1];
- temp3 = ((UInt32 *) srcPtr)[2];
- temp4 = ((UInt32 *) srcPtr)[3];
- ((UInt32 *) destPtr)[0] = temp1;
- ((UInt32 *) destPtr)[1] = temp2;
- ((UInt32 *) destPtr)[2] = temp3;
- ((UInt32 *) destPtr)[3] = temp4;
- srcPtr += 16;
- destPtr += 16;
- }
- // move any remaining data, up to 15 bytes total
- if (miscCounter & 0x8)
- {
- register UInt32 temp1, temp2;
- temp1 = ((UInt32 *) srcPtr)[0];
- temp2 = ((UInt32 *) srcPtr)[1];
- ((UInt32 *) destPtr)[0] = temp1;
- ((UInt32 *) destPtr)[1] = temp2;
- srcPtr += 8;
- destPtr += 8;
- }
- if (miscCounter & 0x4)
- {
- register UInt32 temp1;
- temp1 = *((UInt32 *) srcPtr);
- srcPtr +=4;
- *((UInt32 *) destPtr) = temp1;
- destPtr +=4;
- }
- if (miscCounter & 0x2)
- {
- register UInt16 temp1;
- temp1 = *((UInt16 *) srcPtr);
- srcPtr +=2;
- *((UInt16 *) destPtr) = temp1;
- destPtr +=2;
- }
- if (miscCounter & 0x1)
- *destPtr++ = *srcPtr++;
-
- }
-
- // adjust for right clipping
- destPtr += extraCounter;
- srcPtr += extraCounter;
- xCount += extraCounter;
-
- break;
-
- case kSkipPixelsToken:
- destPtr += tokenData;
- srcPtr += tokenData;
-
- xCount += tokenData;
- break;
-
- case kLineStartToken:
- // check to see if we're done drawing
- if (yCount == 0)
- return;
- else
- {
- // set all the counters up
- yCount--;
- xCount = 0;
- // set up the source and destination pointers
- destPtr = destRowStart;
- srcPtr = sourceRowStart;
- destRowStart += gRowBytes;
- sourceRowStart += gRowBytes;
- }
- break;
- case kEndShapeToken:
- return;
- break;
- #if qDebugging
- default:
- // we should never get here
- Debugger();
- break;
- #endif
- }
- } while (true);
- }
-
- /*************************************************************************************
- TGraphic::BackgroundUnclipped
-
- The Background routines work similarly to the standard graphic drawing routines, but
- we keep an additional pointer to the destination graphics world, and we draw from it,
- not the graphic data. Later, we might optimize this routine further as we know the
- two are always in sync.
- *************************************************************************************/
-
- void
- TGraphic::BackgroundUnclipped (SInt32 top, SInt32 left)
- {
- UInt8 *destRowStart; // the pointer to the start of this row
- UInt8 *sourceRowStart;
- UInt8 *srcPtr; // the current position in the source pixmap
- UInt8 *destPtr; // the current position in the destination pixmap
- UInt8 *dataPtr; // the current position in the sprite data
- UInt32 miscCounter; // a counter for various purposes
- UInt32 tokenOp; // the op code from the token
- UInt32 tokenData; // the data from the token
-
- // determine characteristics about the pixmap
- destRowStart = gDestBaseAddr + top * gRowBytes + left;
- sourceRowStart = gBackBaseAddr + top * gRowBytes + left;
-
- // move to the start of the graphic data
- dataPtr = (UInt8 *)( *fImage );
-
- #if qDebugging
- srcPtr = (UInt8 *) 0xDDDDDDDD;
- destPtr = (UInt8 *) 0xDDDDDDDD;
- #else
- srcPtr = sourceRowStart;
- destPtr = destRowStart;
- #endif
-
- // loop until we are done
- do
- {
- // get a token
- tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
- tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
- dataPtr += sizeof( UInt32 );
-
- // depending on the token
- switch( tokenOp )
- {
- case kDrawPixelsToken:
- miscCounter = tokenData;
- // adjust the data pointer
- tokenData = ALIGN_TO_NEXT_LONG (tokenData);
- dataPtr += tokenData;
-
- // This blit loop is optimized to move 32 bytes or less. On 604 machines, using an 8 byte move
- // is faster in those rare cases where you can get them to align, and way slower when they don't.
- // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
-
-
- {
- register UInt32 sixteenblits, blitloop;
- sixteenblits = miscCounter >> 4;
- for ( blitloop = 0; blitloop < sixteenblits; blitloop++)
- {
- register UInt32 temp1, temp2, temp3, temp4;
- temp1 = ((UInt32 *) srcPtr)[0];
- temp2 = ((UInt32 *) srcPtr)[1];
- temp3 = ((UInt32 *) srcPtr)[2];
- temp4 = ((UInt32 *) srcPtr)[3];
- ((UInt32 *) destPtr)[0] = temp1;
- ((UInt32 *) destPtr)[1] = temp2;
- ((UInt32 *) destPtr)[2] = temp3;
- ((UInt32 *) destPtr)[3] = temp4;
- srcPtr += 16;
- destPtr += 16;
- }
- // move any remaining data, up to 15 bytes total
- if (miscCounter & 0x8)
- {
- register UInt32 temp1, temp2;
- temp1 = ((UInt32 *) srcPtr)[0];
- temp2 = ((UInt32 *) srcPtr)[1];
- ((UInt32 *) destPtr)[0] = temp1;
- ((UInt32 *) destPtr)[1] = temp2;
- srcPtr += 8;
- destPtr += 8;
- }
- if (miscCounter & 0x4)
- {
- register UInt32 temp1;
- temp1 = *((UInt32 *) srcPtr);
- srcPtr +=4;
- *((UInt32 *) destPtr) = temp1;
- destPtr +=4;
- }
- if (miscCounter & 0x2)
- {
- register UInt16 temp1;
- temp1 = *((UInt16 *) srcPtr);
- srcPtr +=2;
- *((UInt16 *) destPtr) = temp1;
- destPtr +=2;
- }
- if (miscCounter & 0x1)
- *destPtr++ = *srcPtr++;
-
- }
-
- break;
-
- case kSkipPixelsToken:
- destPtr += tokenData;
- srcPtr += tokenData;
- break;
-
- case kLineStartToken:
- // set up the source and destination
- destPtr = destRowStart;
- srcPtr = sourceRowStart;
- destRowStart += gRowBytes;
- sourceRowStart += gRowBytes;
- break;
-
- case kEndShapeToken:
- // signal a loop exit
- return;
- break;
- #ifdef qDebugging
- default:
- // we should never get here
- Debugger();
- break;
- #endif
- }
- } while (true);
- }
-
-
- /*************************************************************************************
- TGraphic::DrawMaskUnclipped
-
- This version of the drawing loop draws black anywhere the draw mask is active.
- Useful for writing a PICT out to disk with the mask information.
- *************************************************************************************/
-
- void
- TGraphic::DrawMaskUnclipped (SInt32 top, SInt32 left)
- {
- UInt8 *destRowStart; // the pointer to the start of this row
- UInt8 *destPtr; // the current position in the destination pixmap
- UInt8 *dataPtr; // the current position in the sprite data
- UInt32 miscCounter; // a counter for various purposes
- UInt32 tokenOp; // the op code from the token
- UInt32 tokenData; // the data from the token
- UInt32 indexSmear;
- UInt32 indexSmear2;
-
- indexSmear = kMaskColorIndex;
- indexSmear |= (kMaskColorIndex << 8);
- indexSmear |= (indexSmear << 16);
-
- indexSmear2 = indexSmear;
-
- // determine characteristics about the pixmap
- destRowStart = gDestBaseAddr + top * gRowBytes + left;
-
- // move to the start of the graphic data
- dataPtr = (UInt8 *)( *fImage );
-
- #if qDebugging
- destPtr = (UInt8 *) 0xDDDDDDDD;
- #else
- destPtr = (UInt8 *) destRowStart;
- #endif
-
- // loop until we are done
- do
- {
- // get a token
- tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
- tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
- dataPtr += sizeof( UInt32 );
-
- // depending on the token
- switch( tokenOp )
- {
- case kDrawPixelsToken:
- miscCounter = tokenData;
- // adjust the data pointer
- tokenData = ALIGN_TO_NEXT_LONG (tokenData);
- dataPtr += tokenData;
- // This blit loop is optimized to move 32 bytes or less. On 604 machines, using an 8 byte move
- // is faster in those rare cases where you can get them to align, and way slower when they don't.
- // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
-
-
- {
- register UInt32 sixteenblits, blitloop;
- sixteenblits = miscCounter >> 4;
- for (blitloop = 0; blitloop < sixteenblits; blitloop++)
- {
- ((UInt32 *) destPtr)[0] = *((UInt32 *) &indexSmear);
- ((UInt32 *) destPtr)[1] = *((UInt32 *) &indexSmear);
- ((UInt32 *) destPtr)[2] = *((UInt32 *) &indexSmear);
- ((UInt32 *) destPtr)[3] = *((UInt32 *) &indexSmear);
- destPtr += 16;
- }
- // move any remaining data, up to 15 bytes total
- if (miscCounter & 0x8)
- {
- ((UInt32 *) destPtr)[0] = *((UInt32 *) &indexSmear);
- ((UInt32 *) destPtr)[1] = *((UInt32 *) &indexSmear);
- destPtr += 8;
- }
- if (miscCounter & 0x4)
- {
- *((UInt32 *) destPtr) = *((UInt32 *) &indexSmear);
- destPtr +=4;
- }
- if (miscCounter & 0x2)
- {
- *((UInt16 *) destPtr) = *((UInt16 *) &indexSmear);
- destPtr +=2;
- }
- if (miscCounter & 0x1)
- *destPtr++ = *((UInt8 *) &indexSmear);
-
- }
-
- break;
-
- case kSkipPixelsToken:
- destPtr += tokenData;
- break;
-
- case kLineStartToken:
- // set up the source and destination
- destPtr = destRowStart;
- destRowStart += gRowBytes;
- break;
-
- case kEndShapeToken:
- // signal a loop exit
- return;
- break;
- #ifdef qDebugging
- default:
- // we should never get here
- Debugger();
- break;
- #endif
- }
- } while (true);
- }
-
- /*************************************************************************************
- TGraphic::HitMaskUnclipped
-
- Same as DrawMaskUnclipped, but using the fHitMask data instead.
- *************************************************************************************/
-
- void
- TGraphic::HitMaskUnclipped (SInt32 top, SInt32 left)
- {
- UInt8 *destRowStart; // the pointer to the start of this row
- UInt8 *destPtr; // the current position in the destination pixmap
- UInt8 *dataPtr; // the current position in the sprite data
- UInt32 miscCounter; // a counter for various purposes
- UInt32 tokenOp; // the op code from the token
- UInt32 tokenData; // the data from the token
- UInt32 indexSmear;
- UInt32 indexSmear2;
-
- indexSmear = kMaskColorIndex;
- indexSmear |= (kMaskColorIndex << 8);
- indexSmear |= (indexSmear << 16);
-
- indexSmear2 = indexSmear;
-
- // determine characteristics about the pixmap
- destRowStart = gDestBaseAddr + top * gRowBytes + left;
-
- // move to the start of the graphic data
- dataPtr = (UInt8 *)( *fHitMask );
-
- #if qDebugging
- destPtr = (UInt8 *) 0xDDDDDDDD;
- #else
- destPtr = destRowStart;
- #endif
-
- // loop until we are done
- do
- {
- // get a token
- tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
- tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
- dataPtr += sizeof( UInt32 );
-
- // depending on the token
- switch( tokenOp )
- {
- case kDrawPixelsToken:
- miscCounter = tokenData;
-
- // This blit loop is optimized to move 32 bytes or less. On 604 machines, using an 8 byte move
- // is faster in those rare cases where you can get them to align, and way slower when they don't.
- // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
-
-
- {
- register UInt32 sixteenblits;
- sixteenblits = miscCounter >> 4;
- if (sixteenblits)
- {
- do
- {
- ((UInt32 *) destPtr)[0] = *((UInt32 *) &indexSmear);
- ((UInt32 *) destPtr)[1] = *((UInt32 *) &indexSmear);
- ((UInt32 *) destPtr)[2] = *((UInt32 *) &indexSmear);
- ((UInt32 *) destPtr)[3] = *((UInt32 *) &indexSmear);
- destPtr += 16;
- } while (--sixteenblits != 0);
- }
- // move any remaining data, up to 15 bytes total
- if (miscCounter & 0x8)
- {
- ((UInt32 *) destPtr)[0] = *((UInt32 *) &indexSmear);
- ((UInt32 *) destPtr)[1] = *((UInt32 *) &indexSmear);
- destPtr += 8;
- }
- if (miscCounter & 0x4)
- {
- *((UInt32 *) destPtr) = *((UInt32 *) &indexSmear);
- destPtr +=4;
- }
- if (miscCounter & 0x2)
- {
- *((UInt16 *) destPtr) = *((UInt16 *) &indexSmear);
- destPtr +=2;
- }
- if (miscCounter & 0x1)
- *destPtr++ = *((UInt8 *) &indexSmear);
-
- }
-
- break;
-
- case kSkipPixelsToken:
- destPtr += tokenData;
- break;
-
- case kLineStartToken:
- // set up the source and destination
- destPtr = destRowStart;
- destRowStart += gRowBytes;
- break;
-
- case kEndShapeToken:
- // signal a loop exit
- return;
- break;
- #ifdef qDebugging
- default:
- // we should never get here
- Debugger();
- break;
- #endif
- }
- } while (true);
- }
-
-